package impl

import (
	"context"
	"errors"

	"gitee.com/lcc_dr/restful-api-demo/apps/host"
	"github.com/go-playground/validator/v10"
	"github.com/infraboard/mcube/sqlbuilder"
)

func (h *HostServiceImpl) createHost(ctx context.Context, ins *host.Host) (*host.Host, error) {

	db_tx, err := h.data.BeginTx(ctx, nil)

	if err != nil {
		h.l.Errorf("failed to begin  database  ctx,error reason: %v", err)
		return nil, err
	}
	defer func() {
		if err != nil {
			if err := db_tx.Rollback(); err != nil {
				h.l.Error("rollback error, %s", err)
			}
		} else {
			if err := db_tx.Commit(); err != nil {
				h.l.Error("commit error, %s", err)
			}
		}
	}()
	// 插入Resource数据
	rstmt, err := db_tx.PrepareContext(ctx, InsertResourceSQL)
	if err != nil {
		h.l.Errorf("failed to begin createHost prepare,error reason is: %v", err)
		return nil, err
	}
	defer rstmt.Close()

	_, err = rstmt.ExecContext(ctx,
		ins.Id, ins.Vendor, ins.Region, ins.CreateAt, ins.ExpireAt, ins.Type,
		ins.Name, ins.Description, ins.Status, ins.UpdateAt, ins.SyncAt, ins.Account, ins.PublicIP,
		ins.PrivateIP,
	)
	if err != nil {
		h.l.Errorf("failed to begin createHost  InsertResourceSQL Exec,error reason is: %v", err)
		return nil, err
	}

	// 插入Describe 数据
	dstmt, err := db_tx.PrepareContext(ctx, InsertDescribeSQL)
	if err != nil {
		h.l.Errorf("failed to begin createHost Exec,error reason is: %v", err)
		return nil, err
	}
	defer dstmt.Close()

	_, err = dstmt.ExecContext(ctx,
		ins.Id, ins.CPU, ins.Memory, ins.GPUAmount, ins.GPUSpec,
		ins.OSType, ins.OSName, ins.SerialNumber,
	)
	if err != nil {
		h.l.Errorf("failed to begin createHost Exec InsertDescribeSQL ,error reason is: %v", err)
		return nil, err
	}
	return nil, nil
}

func (h *HostServiceImpl) queryHosts(ctx context.Context, req *host.QueryHostsRequest) (*host.HostSet, error) {

	builder := sqlbuilder.NewBuilder(querytml)

	/*
		// 插入Resource数据
		// querytmt, err := db_tx.Prepare(`SELECT * FROM resource as r LEFT JOIN host h ON r.id=h.resource_id `)
		querytmt, err := db_tx.Prepare(queryHostSQL)
		if err != nil {
			h.l.Errorf("failed to begin createHost prepare,error reason is: %v", err)
			return nil, err
		}
		defer querytmt.Close()

	*/

	name := "%" + req.Name + "%"
	description := "%" + req.Description + "%"
	public_ip := "%" + req.PublicIP + "%"

	offset := (req.PageNumber - 1) * req.PageSize

	builder.Where("r.`name` LIKE ? AND r.description LIKE ?  AND r.public_ip LIKE ?", name, description, public_ip)
	// builder.Where("r.`name` LIKE ? ", name)
	builder.Limit(int64(offset), uint(req.PageSize))
	querySQL, args := builder.Build()
	h.l.Debugf("qusql is %v args is %v", querySQL, args)

	stmt, err := h.data.PrepareContext(ctx, querySQL)
	if err != nil {
		return nil, err
	}
	defer stmt.Close()

	rows, err := stmt.QueryContext(ctx, args...)
	if err != nil {
		return nil, err
	}

	// rows, err := querytmt.Query()

	if err != nil {
		h.l.Errorf("failed to begin createHost  InsertResourceSQL Exec,error reason is: %v", err)
		return nil, err
	}
	hosts := host.NewHostSet()

	for rows.Next() {
		host := host.Newhost()
		err := rows.Scan(&host.Id, &host.Vendor, &host.Region, &host.CreateAt, &host.ExpireAt, &host.Type, &host.Name,
			&host.Description, &host.Status, &host.UpdateAt, &host.SyncAt, &host.Account, &host.PublicIP, &host.PrivateIP,

			&host.PrivateIP, &host.CPU, &host.Memory, &host.GPUAmount, &host.GPUSpec, &host.OSType, &host.OSName, &host.SerialNumber,
		)
		if err != nil {
			return nil, err
		}
		hosts.Items = append(hosts.Items, host)
	}

	builder.BuildCount()

	querytotal, args := builder.BuildCount()

	h.l.Debugf("queryToatltmt is %v,args is%v", querytotal, args)

	var total int64
	stmt, err = h.data.PrepareContext(ctx, querytotal)
	if err != nil {
		return nil, err
	}
	defer stmt.Close()
	rows, err = stmt.QueryContext(ctx, args...)
	for rows.Next() {

		err := rows.Scan(&total)
		if err != nil {
			return nil, err
		}

	}
	hosts.Total = total

	return hosts, nil
}

func (h *HostServiceImpl) querydescribeHost(ctx context.Context, req *host.DescribeHostRequest) (*host.Host, error) {

	desStmt, err := h.data.Prepare(describeHostSQL)
	defer desStmt.Close()
	if err != nil {

		return nil, err
	}

	host := host.Newhost()
	err = desStmt.QueryRowContext(ctx, req.ID).Scan(&host.Id, &host.Vendor, &host.Region, &host.CreateAt, &host.ExpireAt, &host.Type, &host.Name,
		&host.Description, &host.Status, &host.UpdateAt, &host.SyncAt, &host.Account, &host.PublicIP, &host.PrivateIP,

		&host.PrivateIP, &host.CPU, &host.Memory, &host.GPUAmount, &host.GPUSpec, &host.OSType, &host.OSName, &host.SerialNumber,
	)
	if err != nil {
		h.l.Infof("query host form id error: %v", err)
		return nil, err
	}

	return host, nil

}

func (h *HostServiceImpl) deleteHost(ctx context.Context, req *host.DeleteHostRequest) (*host.Host, error) {

	//1、删除前先查询下
	//2、不存在即返回
	//3、存在执行删除
	//4、删除完再查询确认已删除

	db_tx, err := h.data.BeginTx(ctx, nil)

	if err != nil {
		return nil, err
	}

	defer func() {
		if err != nil {
			if err := db_tx.Rollback(); err != nil {
				h.l.Error("rollback error, %s", err)
			}
		} else {
			if err := db_tx.Commit(); err != nil {
				h.l.Error("commit error, %s", err)
			}
		}
	}()

	//删除resource
	ResStmt, err := db_tx.PrepareContext(ctx, deleteResourceSQL)
	if err != nil {
		return nil, err
	}
	_, err = ResStmt.ExecContext(ctx, req.ID)
	if err != nil {
		return nil, err
	}

	//删除host
	HostStmt, err := db_tx.PrepareContext(ctx, deleteHostSQL)
	if err != nil {
		return nil, err
	}
	_, err = HostStmt.ExecContext(ctx, req.ID)
	if err != nil {
		return nil, err
	}

	return nil, nil

}

// update patch
func (h *HostServiceImpl) updatePatchHost(ctx context.Context, req *host.UpdatePatchHostRequest) (*host.Host, error) {

	query := host.NewDescribeHostRequest()
	query.ID = req.ID
	ins, err := h.querydescribeHost(ctx, query)
	if err != nil {
		return ins, errors.New("update patch host: query id failed: ")
	}

	if req.Name != "" {
		ins.Name = req.Name
	}

	if req.Region != "" {
		ins.Region = req.Region

	}
	if req.CPU != 0 {
		ins.CPU = req.CPU
	}
	if req.Memory != 0 {
		ins.Memory = req.Memory

	}

	db_tx, err := h.data.BeginTx(ctx, nil)

	if err != nil {
		return nil, err
	}

	defer func() {
		if err != nil {
			if err := db_tx.Rollback(); err != nil {
				h.l.Error("rollback error, %s", err)
			}
		} else {
			if err := db_tx.Commit(); err != nil {
				h.l.Error("commit error, %s", err)
			}
		}
	}()

	//更新host
	HostStmt, err := db_tx.PrepareContext(ctx, updateHostSQL)
	if err != nil {
		return nil, err
	}
	_, err = HostStmt.ExecContext(ctx, ins.CPU, ins.Memory, req.ID)
	if err != nil {
		return nil, err
	}

	//更新resource
	ResStmt, err := db_tx.PrepareContext(ctx, updateResourceSQL)
	if err != nil {
		return nil, err
	}
	_, err = ResStmt.ExecContext(ctx, ins.Name, ins.Region, req.ID)
	if err != nil {
		return nil, err
	}

	var validate *validator.Validate
	//ins参数校验
	validate = validator.New()
	err = validate.Struct(ins)
	if err != nil {
		return nil, err
	}

	return ins, nil
}

//update put
func (h *HostServiceImpl) updatePutHost(ctx context.Context, req *host.UpdatePutHostRequest) (*host.Host, error) {

	query := host.NewDescribeHostRequest()
	query.ID = req.Host.Id
	ins, err := h.querydescribeHost(ctx, query)
	if err != nil {
		return ins, errors.New("update patch host: query id failed: ")
	}

	*ins.Resource = *req.Resource
	*ins.Describe = *req.Describe

	db_tx, err := h.data.BeginTx(ctx, nil)

	if err != nil {
		return nil, err
	}

	defer func() {
		if err != nil {
			if err := db_tx.Rollback(); err != nil {
				h.l.Error("rollback error, %s", err)
			}
		} else {
			if err := db_tx.Commit(); err != nil {
				h.l.Error("commit error, %s", err)
			}
		}
	}()

	//更新host
	HostStmt, err := db_tx.PrepareContext(ctx, updateHostSQL)
	if err != nil {
		return nil, err
	}
	_, err = HostStmt.ExecContext(ctx, ins.CPU, ins.Memory, ins.Id)
	if err != nil {
		return nil, err
	}

	//更新resource
	ResStmt, err := db_tx.PrepareContext(ctx, updateResourceSQL)
	if err != nil {
		return nil, err
	}
	_, err = ResStmt.ExecContext(ctx, ins.Name, ins.Region, ins.Id)
	if err != nil {
		return nil, err
	}

	var validate *validator.Validate
	//ins参数校验
	validate = validator.New()
	err = validate.Struct(ins)
	if err != nil {
		return nil, err
	}

	return ins, nil
}
